package ua.tach.shortl.logic;

import java.util.ArrayList;

import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;

public class Train {
	public static final float RENDERSIZE = 0.3f;
	public static final float WAGONSIZE = RENDERSIZE * Rail.BASERAILSIZE;
	public static ArrayList<Wagon> wpool = new ArrayList<Wagon>();

	public Vector3 owner;
	public float speed;
	public float maxSpeed;
	public int stopCounter;
	public boolean movingDirection; // true - forward, false - backward
	public boolean reqToTurn;
	public boolean waiting;
	private ArrayList<Wagon> wagon = new ArrayList<Wagon>();
	public int trainSize;
	public final Vector2 head = new Vector2();

	private TrainSet[] vartrains = {
			new TrainSet(1799,1950,0,6,6,-1,-1),
			new TrainSet(1799,1960,0,-1,-1,-1,-1),
			new TrainSet(1799,1950,0,4,5,4,-1),
			new TrainSet(1799,1950,0,4,5,4,6),
			new TrainSet(1930,2001,1,3,3,-1,-1),
			new TrainSet(1930,2001,1,3,-1,-1,-1),
	};

	public Train () {
	}

	public Train (int c, RailPosition nr, float speed) {
		RailPosition r = new RailPosition(nr);
		owner = Country.getTrainColor(Country.CITY_COLORS[c]);
		//System.out.println("Color "+c);
		movingDirection = true;
		this.speed  = speed;
		maxSpeed = speed;
		r.train = this;
		trainSize = 0;
		waiting = true;
		while (true) {
			int v = Country.randomGenerator.nextInt(vartrains.length);
			if (!vartrains[v].allow(Country.Counters[0])) continue;
			wagon.add(getWagon(vartrains[v].loco , r, this));

			for (int t : vartrains[v].w ) {
				if (t == -1) break;
				// calculate next wagon position
				r = new RailPosition(r);
				r.pos -= WAGONSIZE ;
				wagon.add(getWagon(t, r, this));
				++trainSize;
			}
			break;
		}
		tick(); // to calculate correct screen position
	}

	protected static Wagon getWagon(int type, RailPosition r, Train owner) {
		for (Wagon w : wpool) {
			if (w.isFree) {
				w.setWagon(type, r, owner);
				System.out.println(" Train from pool");
				return w;
			}
		}
		Wagon w1 = new Wagon(type, r, owner);
		wpool.add(w1);
		System.out.println(" New train ");
		return w1;
	}

	public void dispose() {
		returnWagon(this);
	}

	public static void returnWagon(Train owner) {
		for(Wagon w : owner.wagon )
			w.isFree = true;
	}

	private boolean checkCrash(Wagon first) {
		// calculate head
		head.set( first.current.renderCoord.x, first.current.renderCoord.y);

		for (CrashPlace c : Country.crashes) {
			if (c.dist(head) < RENDERSIZE/2)
				return true;
		}

		return wagonCrash(first.current.base);
	}

	protected boolean wagonCrash(Rail b) {
		for (Wagon w : Train.wpool) {
			if(w.isFree || w.train == this || w.train.waiting) continue;
			if (w.current.renderCoord.dst(head) < RENDERSIZE/3) {
				// Ignore trains on connected rails
				if(w.current.base.isNeighbor(b)) {
					System.out.println(" On switch! ");
					continue;
				}
				Country.crashes.add(new CrashPlace(new Vector2(head)));
				System.out.println(" Crash ");
				Country.removeTrain(w.train);
				return true;
			}
		}
		return false;
	}

	public boolean tick () {
		reqToTurn = false;

		// check for speed change
		if(!wagon.isEmpty()) wagon.get((movingDirection)?0:wagon.size()-1).checkWay();

		for(Wagon w : wagon)
			w.tick();

		if(reqToTurn)
			movingDirection = !movingDirection ;

		if(!wagon.isEmpty() && !waiting) { // check for collision and depot
			if (checkCrash(wagon.get((movingDirection)?0:wagon.size()-1)))
				return true;

			if(wagon.get(wagon.size()-1).current.atDepot && wagon.get(0).current.atDepot) { // all wagons in depot?
				// Check color
				if (wagon.get(0).current.base.checkColor(owner)) {
					++Country.Counters[1];
					Country.bank.trainArrv(wagon.size());
					System.out.println("Train at home! ");
					return true;
				} else
					movingDirection = !movingDirection ; // not for me -> turn back
			}
		}
		return false;
	}

	public void render (GL10 gl) {
		for(Wagon w : wagon)
			w.render(gl);
	}

	public static class NullTrain extends Train implements Null {
		private NullTrain () {
		}
		public void render (GL10 gl) {
		}
	}

	public static final Train NULL = new NullTrain();

}
